package com.ruoyi.system.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.math.BigDecimal;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.BizReceiptBarcode;
import com.ruoyi.system.domain.BizBarcode;
import com.ruoyi.system.mapper.BizReceiptNoteMapper;
import com.ruoyi.system.mapper.BizBarcodeMapper;
import com.ruoyi.system.mapper.BizInspectionPlanMapper;
import com.ruoyi.system.mapper.BizInspectionTemplateMapper;
import com.ruoyi.system.domain.BizReceiptNote;
import com.ruoyi.system.service.IBizReceiptNoteService;
import com.ruoyi.system.mapper.BizPurchaseOrderMapper;
import com.ruoyi.system.domain.BizPurchaseOrderItem;
import com.ruoyi.system.domain.BizInspectionPlan;
import com.ruoyi.system.domain.BizInspectionTemplate;

/**
 * 收料通知单Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-27
 */
@Service
public class BizReceiptNoteServiceImpl implements IBizReceiptNoteService 
{
    @Autowired
    private BizReceiptNoteMapper bizReceiptNoteMapper;

    @Autowired
    private BizBarcodeMapper bizBarcodeMapper;

    @Autowired
    private BizPurchaseOrderMapper bizPurchaseOrderMapper;

    @Autowired
    private BizInspectionPlanMapper bizInspectionPlanMapper;

    @Autowired
    private BizInspectionTemplateMapper bizInspectionTemplateMapper;

    /**
     * 查询收料通知单
     * 
     * @param receiptNoteId 收料通知单主键
     * @return 收料通知单
     */
    @Override
    public BizReceiptNote selectBizReceiptNoteByReceiptNoteId(Long receiptNoteId)
    {
        return bizReceiptNoteMapper.selectBizReceiptNoteByReceiptNoteId(receiptNoteId);
    }

    /**
     * 查询收料通知单列表
     * 
     * @param bizReceiptNote 收料通知单
     * @return 收料通知单
     */
    @Override
    public List<BizReceiptNote> selectBizReceiptNoteList(BizReceiptNote bizReceiptNote)
    {
        return bizReceiptNoteMapper.selectBizReceiptNoteList(bizReceiptNote);
    }

    /**
     * 新增收料通知单
     * 
     * @param bizReceiptNote 收料通知单
     * @return 结果
     */
    @Transactional
    @Override
    public int insertBizReceiptNote(BizReceiptNote bizReceiptNote)
    {
        // 1) 生成收料通知单编号 RNyyyyMMddNNN
        String today = DateUtils.parseDateToStr("yyyyMMdd", DateUtils.getNowDate());
        String prefix = "RN" + today;
        String maxNo = bizReceiptNoteMapper.selectMaxReceiptNoteNoByDate(prefix);
        int seq = 1;
        if (StringUtils.isNotEmpty(maxNo) && maxNo.length() >= prefix.length() + 3) {
            String s = maxNo.substring(prefix.length());
            try { seq = Integer.parseInt(s) + 1; } catch (Exception ignore) { seq = 1; }
        }
        String nextNo = prefix + String.format("%03d", seq);
        bizReceiptNote.setReceiptNoteNo(nextNo);

        // 2) 状态与审计字段
        if (StringUtils.isEmpty(bizReceiptNote.getReceiptStatus())) {
            bizReceiptNote.setReceiptStatus("CREATED");
        }
        if (bizReceiptNote.getReceivedTime() == null) {
            bizReceiptNote.setReceivedTime(DateUtils.getNowDate());
        }
        // 新增默认收料日期：为空时赋当前日期
        if (bizReceiptNote.getReceiptDate() == null) {
            bizReceiptNote.setReceiptDate(DateUtils.getNowDate());
        }
        bizReceiptNote.setCreatedBy(SecurityUtils.getUsername());
        bizReceiptNote.setCreatedTime(DateUtils.getNowDate());

        // 3) 计算总箱数与总数量（基于前端传入的箱码明细）
        Long totalBoxes = 0L;
        BigDecimal totalQuantity = BigDecimal.ZERO;
        List<BizReceiptBarcode> srcList = bizReceiptNote.getBizReceiptBarcodeList();
        if (StringUtils.isNotNull(srcList)) {
            for (BizReceiptBarcode rb : srcList) {
                totalBoxes += 1;
                if (rb.getPackQuantity() != null) {
                    totalQuantity = totalQuantity.add(rb.getPackQuantity());
                }
            }
        }
        bizReceiptNote.setTotalBoxes(totalBoxes);
        bizReceiptNote.setTotalQuantity(totalQuantity);

        // 4) 插入主表，获取 receiptNoteId
        int rows = bizReceiptNoteMapper.insertBizReceiptNote(bizReceiptNote);

        // 5) 组装箱码明细并批量插入，同时更新箱码主表状态为 RECEIVED
        insertBizReceiptBarcode(bizReceiptNote);

        // 6) 根据累计已收数量更新采购订单明细状态（PART_RECEIVED / FULL_RECEIVED）
        updatePurchaseOrderItemReceiveStatus(bizReceiptNote.getBizReceiptBarcodeList());

        // 7) 基于本次收料的箱码分组生成来料检验计划，并将箱码状态更新为 INSPECTING
        createInspectionPlansForReceipt(bizReceiptNote);

        return rows;
    }

    /**
     * 修改收料通知单
     * 
     * @param bizReceiptNote 收料通知单
     * @return 结果
     */
    @Transactional
    @Override
    public int updateBizReceiptNote(BizReceiptNote bizReceiptNote)
    {
        // 更新人和更新时间
        bizReceiptNote.setUpdatedBy(SecurityUtils.getUsername());
        bizReceiptNote.setUpdatedTime(DateUtils.getNowDate());

        // 重新计算总箱数与总数量（基于前端传入的箱码明细）
        Long totalBoxes = 0L;
        BigDecimal totalQuantity = BigDecimal.ZERO;
        List<BizReceiptBarcode> srcList = bizReceiptNote.getBizReceiptBarcodeList();
        if (StringUtils.isNotNull(srcList)) {
            for (BizReceiptBarcode rb : srcList) {
                totalBoxes += 1;
                if (rb.getPackQuantity() != null) {
                    totalQuantity = totalQuantity.add(rb.getPackQuantity());
                }
            }
        }
        bizReceiptNote.setTotalBoxes(totalBoxes);
        bizReceiptNote.setTotalQuantity(totalQuantity);

        // 先删除旧明细，再写入新明细
        bizReceiptNoteMapper.deleteBizReceiptBarcodeByReceiptNoteId(bizReceiptNote.getReceiptNoteId());
        insertBizReceiptBarcode(bizReceiptNote);

        // 新增：根据累计已收数量更新采购订单明细状态
        updatePurchaseOrderItemReceiveStatus(bizReceiptNote.getBizReceiptBarcodeList());

        // 更新主表
        return bizReceiptNoteMapper.updateBizReceiptNote(bizReceiptNote);
    }

    /**
     * 批量删除收料通知单
     * 
     * @param receiptNoteIds 需要删除的收料通知单主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteBizReceiptNoteByReceiptNoteIds(Long[] receiptNoteIds)
    {
        bizReceiptNoteMapper.deleteBizReceiptBarcodeByReceiptNoteIds(receiptNoteIds);
        return bizReceiptNoteMapper.deleteBizReceiptNoteByReceiptNoteIds(receiptNoteIds);
    }

    /**
     * 删除收料通知单信息
     * 
     * @param receiptNoteId 收料通知单主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteBizReceiptNoteByReceiptNoteId(Long receiptNoteId)
    {
        bizReceiptNoteMapper.deleteBizReceiptBarcodeByReceiptNoteId(receiptNoteId);
        return bizReceiptNoteMapper.deleteBizReceiptNoteByReceiptNoteId(receiptNoteId);
    }

    /**
     * 新增收料通知单箱码明细信息
     * 
     * @param bizReceiptNote 收料通知单对象
     */
    public void insertBizReceiptBarcode(BizReceiptNote bizReceiptNote)
    {
        List<BizReceiptBarcode> bizReceiptBarcodeList = bizReceiptNote.getBizReceiptBarcodeList();
        Long receiptNoteId = bizReceiptNote.getReceiptNoteId();
        String receiptNoteNo = bizReceiptNote.getReceiptNoteNo();
        if (StringUtils.isNotNull(bizReceiptBarcodeList) && !bizReceiptBarcodeList.isEmpty())
        {
            List<BizReceiptBarcode> list = new ArrayList<BizReceiptBarcode>();
            List<Long> barcodeIds = new ArrayList<>();
            for (BizReceiptBarcode src : bizReceiptBarcodeList)
            {
                BizBarcode bc = null;
                if (src.getBarcodeId() != null) {
                    bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(src.getBarcodeId());
                }

                BizReceiptBarcode item = new BizReceiptBarcode();
                item.setReceiptNoteId(receiptNoteId);
                item.setReceiptNoteNo(receiptNoteNo);
                item.setBarcodeId(src.getBarcodeId());
                item.setBarcode(src.getBarcode());
                item.setItemId(bc != null ? bc.getItemId() : src.getItemId());
                item.setOrderNo(bc != null ? bc.getOrderNo() : src.getOrderNo());
                item.setInventoryCode(bc != null ? bc.getInventoryCode() : src.getInventoryCode());
                item.setBatchNo(bc != null ? bc.getBatchNo() : src.getBatchNo());
                item.setPackQuantity(bc != null ? bc.getPackQuantity() : src.getPackQuantity());
                item.setUnitCode(bc != null ? bc.getUnitCode() : src.getUnitCode());
                item.setBarcodeStatus("RECEIVED");
                item.setCreatedBy(SecurityUtils.getUsername());
                item.setCreatedTime(DateUtils.getNowDate());
                list.add(item);
                if (src.getBarcodeId() != null) {
                    barcodeIds.add(src.getBarcodeId());
                }
            }
            if (list.size() > 0)
            {
                bizReceiptNoteMapper.batchBizReceiptBarcode(list);
            }
            if (!barcodeIds.isEmpty()) {
                bizBarcodeMapper.batchUpdateReceivedStatus(
                    receiptNoteNo,
                    DateUtils.getNowDate(),
                    barcodeIds.toArray(new Long[0])
                );
            }
        }
    }

    // 新增：根据累计已收数量更新采购订单明细状态
    private void updatePurchaseOrderItemReceiveStatus(List<BizReceiptBarcode> srcList) {
        if (StringUtils.isNull(srcList) || srcList.isEmpty()) {
            return;
        }
        java.util.Set<Long> itemIds = new java.util.HashSet<>();
        for (BizReceiptBarcode rb : srcList) {
            if (rb.getItemId() != null) {
                itemIds.add(rb.getItemId());
            }
        }
        if (itemIds.isEmpty()) {
            return;
        }
        String updatedBy = SecurityUtils.getUsername();
        java.util.Date updatedTime = DateUtils.getNowDate();
        for (Long itemId : itemIds) {
            BizPurchaseOrderItem poi = bizPurchaseOrderMapper.selectBizPurchaseOrderItemByItemId(itemId);
            if (poi == null || poi.getOrderQuantity() == null) {
                continue;
            }
            BigDecimal received = bizBarcodeMapper.selectSumReceivedQuantityByItemId(itemId);
            if (received == null) received = BigDecimal.ZERO;
            String newStatus = null;
            if (received.compareTo(poi.getOrderQuantity()) >= 0) {
                newStatus = "FULL_RECEIVED";
            } else if (received.compareTo(BigDecimal.ZERO) > 0) {
                newStatus = "PART_RECEIVED";
            }
            if (newStatus != null) {
                bizPurchaseOrderMapper.updateBizPurchaseOrderItemStatus(itemId, newStatus, updatedBy, updatedTime);
            }
        }
    }

    /**
     * 基于本次收料的箱码分组，创建来料检验计划并更新箱码的检验状态与计划号
     */
    private void createInspectionPlansForReceipt(BizReceiptNote note) {
        List<BizReceiptBarcode> srcList = note.getBizReceiptBarcodeList();
        if (StringUtils.isNull(srcList) || srcList.isEmpty()) {
            return;
        }
        java.util.Map<String, java.util.List<BizBarcode>> groups = new java.util.HashMap<>();
        for (BizReceiptBarcode src : srcList) {
            BizBarcode bc = null;
            if (src.getBarcodeId() != null) {
                bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(src.getBarcodeId());
            }
            String inventoryCode = bc != null ? bc.getInventoryCode() : src.getInventoryCode();
            String batchNo = bc != null ? bc.getBatchNo() : src.getBatchNo();
            if (StringUtils.isEmpty(inventoryCode)) {
                // 无法分组的记录跳过
                continue;
            }
            String key = inventoryCode + "#" + (batchNo == null ? "" : batchNo);
            java.util.List<BizBarcode> list = groups.computeIfAbsent(key, k -> new java.util.ArrayList<>());
            if (bc != null) {
                list.add(bc);
            } else {
                BizBarcode stub = new BizBarcode();
                stub.setBarcodeId(src.getBarcodeId());
                stub.setInventoryCode(inventoryCode);
                stub.setBatchNo(batchNo);
                stub.setPackQuantity(src.getPackQuantity());
                stub.setOrderNo(src.getOrderNo());
                stub.setItemId(src.getItemId());
                list.add(stub);
            }
        }

        if (groups.isEmpty()) {
            return;
        }

        String username = SecurityUtils.getUsername();
        java.util.Date now = DateUtils.getNowDate();
        String today = DateUtils.parseDateToStr("yyyyMMdd", now);

        for (java.util.Map.Entry<String, java.util.List<BizBarcode>> entry : groups.entrySet()) {
            java.util.List<BizBarcode> groupBarcodes = entry.getValue();
            if (groupBarcodes == null || groupBarcodes.isEmpty()) continue;
            BizBarcode first = groupBarcodes.get(0);
            String inventoryCode = first.getInventoryCode();
            String batchNo = first.getBatchNo();
            String inventoryName = first.getInventoryName();
            String supplierCode = first.getSupplierCode();
            String supplierName = first.getSupplierName();
            String deliveryNoteNo = first.getDeliveryNoteNo();

            Long totalBoxes = (long) groupBarcodes.size();
            BigDecimal totalQuantity = BigDecimal.ZERO;
            java.util.List<Long> barcodeIds = new java.util.ArrayList<>();
            for (BizBarcode b : groupBarcodes) {
                if (b.getPackQuantity() != null) {
                    totalQuantity = totalQuantity.add(b.getPackQuantity());
                }
                if (b.getBarcodeId() != null) {
                    barcodeIds.add(b.getBarcodeId());
                }
            }

            // 选择检验模板（按 inventoryCode 过滤，取第一条）
            BizInspectionTemplate query = new BizInspectionTemplate();
            query.setInventoryCode(inventoryCode);
            List<BizInspectionTemplate> templates = bizInspectionTemplateMapper.selectBizInspectionTemplateList(query);
            BizInspectionTemplate chosen = (templates != null && !templates.isEmpty()) ? templates.get(0) : null;

            // 生成检验计划号 IPyyyyMMddNNN
            String prefix = "IP" + today;
            String maxPlanNo = bizInspectionPlanMapper.selectMaxPlanNoByDate(prefix);
            int seq = 1;
            if (StringUtils.isNotEmpty(maxPlanNo) && maxPlanNo.length() >= prefix.length() + 3) {
                String s = maxPlanNo.substring(prefix.length());
                try { seq = Integer.parseInt(s) + 1; } catch (Exception ignore) { seq = 1; }
            }
            String planNo = prefix + String.format("%03d", seq);

            // 计算抽检箱数与抽检数量（模板 sampleRate 为百分比，需要转换为比例小数）
            Long sampleBoxes = 0L;
            BigDecimal sampleQuantity = BigDecimal.ZERO;
            if (chosen != null && chosen.getSampleRate() != null) {
                // 将百分比转换为比例：例如 10 表示 10%，转换为 0.10
                BigDecimal ratePercent = chosen.getSampleRate();
                BigDecimal rate = ratePercent.divide(new BigDecimal("100"), 8, java.math.RoundingMode.HALF_UP);
                if (rate.compareTo(BigDecimal.ZERO) > 0) {
                    // 抽检箱数：totalBoxes * rate，向上取整，并限制不超过总箱数
                    long sb = new BigDecimal(totalBoxes)
                            .multiply(rate)
                            .setScale(0, java.math.RoundingMode.CEILING)
                            .longValue();
                    if (sb > totalBoxes) {
                        sb = totalBoxes;
                    }
                    // 若比例>0但计算结果为0，且存在箱数，则至少抽检1箱
                    if (sb == 0L && totalBoxes > 0L) {
                        sb = 1L;
                    }
                    sampleBoxes = sb;

                    // 抽检数量：totalQuantity * rate，四舍五入到4位，并限制不超过总数量
                    sampleQuantity = totalQuantity
                            .multiply(rate)
                            .setScale(4, java.math.RoundingMode.HALF_UP);
                    if (sampleQuantity.compareTo(totalQuantity) > 0) {
                        sampleQuantity = totalQuantity;
                    }
                }
            }

            BizInspectionPlan plan = new BizInspectionPlan();
            plan.setPlanNo(planNo);
            plan.setReceiptNoteId(note.getReceiptNoteId());
            plan.setReceiptNoteNo(note.getReceiptNoteNo());
            plan.setDeliveryNoteNo(deliveryNoteNo);
            plan.setSupplierCode(supplierCode);
            plan.setSupplierName(supplierName);
            plan.setInventoryCode(inventoryCode);
            plan.setInventoryName(inventoryName);
            plan.setBatchNo(batchNo);
            plan.setTotalBoxes(totalBoxes);
            plan.setTotalQuantity(totalQuantity);
            // 无论是否存在模板，均写入抽检箱数与抽检数量（为空时默认为0）
            plan.setSampleBoxes(sampleBoxes);
            plan.setSampleQuantity(sampleQuantity);
            if (chosen != null) {
                plan.setTemplateId(chosen.getTemplateId());
                plan.setTemplateNo(chosen.getTemplateNo());
            }
            plan.setPlanStatus("PENDING");
            plan.setCreatedBy(username);
            plan.setCreatedTime(now);
            plan.setUpdatedBy(username);
            plan.setUpdatedTime(now);

            bizInspectionPlanMapper.insertBizInspectionPlan(plan);

            // 更新该分组下所有箱码为检验中并写入检验计划号
            if (!barcodeIds.isEmpty()) {
                bizBarcodeMapper.batchUpdateInspectingStatus(planNo, barcodeIds.toArray(new Long[0]));
            }
        }
    }
}
